package com.navinfo.opentsp.platform.computing.analysis.service;

import com.navinfo.opentsp.platform.computing.analysis.entity.coldChain.ColdChainEvent;
import com.navinfo.opentsp.platform.computing.analysis.entity.coldChain.OutData;
import com.navinfo.opentsp.platform.computing.analysis.entity.coldChain.PointForColdChain;

import java.io.Serializable;
import java.sql.Timestamp;

/**
 * 冷链
 */
public class ColdChainAlgorithmService implements Serializable {
    private static final int OFF = 0;
    private static final int ON = 1;

    public static Timestamp getStartTime(OutData outData, EventType type) {
        switch (type) {
            case TMPRTR1:
                return outData.getPreCargoBoxTemperature1St();
            case TMPRTR2:
                return outData.getPreCargoBoxTemperature2St();
            case TMPRTR3:
                return outData.getPreCargoBoxTemperature3St();
            case TMPRTR4:
                return outData.getPreCargoBoxTemperature4St();
            case HMDT1:
                return outData.getPreContainerHumidity1St();
            case HMDT2:
                return outData.getPreContainerHumidity2St();
            case HMDT3:
                return outData.getPreContainerHumidity3St();
            case HMDT4:
                return outData.getPreContainerHumidity4St();
            case DRSTS1:
                return outData.getPreCargoBoxDoorStatus1St();
            case DRSTS2:
                return outData.getPreCargoBoxDoorStatus2St();
            case DRSTS3:
                return outData.getPreCargoBoxDoorStatus3St();
            default:
                throw new IllegalArgumentException("invalid type:" + type);
        }
    }

    public static Integer getLat(OutData outData, EventType type) {
        switch (type) {
            case TMPRTR1:
                return outData.getPreCargoBoxTemperature1Lat();
            case TMPRTR2:
                return outData.getPreCargoBoxTemperature2Lat();
            case TMPRTR3:
                return outData.getPreCargoBoxTemperature3Lat();
            case TMPRTR4:
                return outData.getPreCargoBoxTemperature4Lat();
            case HMDT1:
                return outData.getPreContainerHumidity1Lat();
            case HMDT2:
                return outData.getPreContainerHumidity2Lat();
            case HMDT3:
                return outData.getPreContainerHumidity3Lat();
            case HMDT4:
                return outData.getPreContainerHumidity4Lat();
            case DRSTS1:
                return outData.getPreCargoBoxDoorStatus1Lat();
            case DRSTS2:
                return outData.getPreCargoBoxDoorStatus2Lat();
            case DRSTS3:
                return outData.getPreCargoBoxDoorStatus3Lat();
            default:
                throw new IllegalArgumentException("invalid type:" + type);
        }
    }

    public static Integer getLon(OutData outData, EventType type) {
        switch (type) {
            case TMPRTR1:
                return outData.getPreCargoBoxTemperature1Lon();
            case TMPRTR2:
                return outData.getPreCargoBoxTemperature2Lon();
            case TMPRTR3:
                return outData.getPreCargoBoxTemperature3Lon();
            case TMPRTR4:
                return outData.getPreCargoBoxTemperature4Lon();
            case HMDT1:
                return outData.getPreContainerHumidity1Lon();
            case HMDT2:
                return outData.getPreContainerHumidity2Lon();
            case HMDT3:
                return outData.getPreContainerHumidity3Lon();
            case HMDT4:
                return outData.getPreContainerHumidity4Lon();
            case DRSTS1:
                return outData.getPreCargoBoxDoorStatus1Lon();
            case DRSTS2:
                return outData.getPreCargoBoxDoorStatus2Lon();
            case DRSTS3:
                return outData.getPreCargoBoxDoorStatus3Lon();
            default:
                throw new IllegalArgumentException("invalid type:" + type);
        }
    }

    public static void setStartInfo(OutData outData, EventType type, Timestamp startTime, Integer lat, Integer lon, int onOff) {
        switch (type) {
            case TMPRTR1:
                outData.setPreCargoBoxTemperature1(onOff);
                outData.setPreCargoBoxTemperature1St(startTime);
                outData.setPreCargoBoxTemperature1Lat(lat);
                outData.setPreCargoBoxTemperature1Lon(lon);
                break;
            case TMPRTR2:
                outData.setPreCargoBoxTemperature2(onOff);
                outData.setPreCargoBoxTemperature2St(startTime);
                outData.setPreCargoBoxTemperature2Lat(lat);
                outData.setPreCargoBoxTemperature2Lon(lon);
                break;
            case TMPRTR3:
                outData.setPreCargoBoxTemperature3(onOff);
                outData.setPreCargoBoxTemperature3St(startTime);
                outData.setPreCargoBoxTemperature3Lat(lat);
                outData.setPreCargoBoxTemperature3Lon(lon);
                break;
            case TMPRTR4:
                outData.setPreCargoBoxTemperature4(onOff);
                outData.setPreCargoBoxTemperature4St(startTime);
                outData.setPreCargoBoxTemperature4Lat(lat);
                outData.setPreCargoBoxTemperature4Lon(lon);
                break;
            case HMDT1:
                outData.setPreContainerHumidity1(onOff);
                outData.setPreContainerHumidity1St(startTime);
                outData.setPreContainerHumidity1Lat(lat);
                outData.setPreContainerHumidity1Lon(lon);
                break;
            case HMDT2:
                outData.setPreContainerHumidity2(onOff);
                outData.setPreContainerHumidity2St(startTime);
                outData.setPreContainerHumidity2Lat(lat);
                outData.setPreContainerHumidity2Lon(lon);
                break;
            case HMDT3:
                outData.setPreContainerHumidity3(onOff);
                outData.setPreContainerHumidity3St(startTime);
                outData.setPreContainerHumidity3Lat(lat);
                outData.setPreContainerHumidity3Lon(lon);
                break;
            case HMDT4:
                outData.setPreContainerHumidity4(onOff);
                outData.setPreContainerHumidity4St(startTime);
                outData.setPreContainerHumidity4Lat(lat);
                outData.setPreContainerHumidity4Lon(lon);
                break;
            case DRSTS1:
                outData.setPreCargoBoxDoorStatus1(onOff);
                outData.setPreCargoBoxDoorStatus1St(startTime);
                outData.setPreCargoBoxDoorStatus1Lat(lat);
                outData.setPreCargoBoxDoorStatus1Lon(lon);
                break;
            case DRSTS2:
                outData.setPreCargoBoxDoorStatus2(onOff);
                outData.setPreCargoBoxDoorStatus2St(startTime);
                outData.setPreCargoBoxDoorStatus2Lat(lat);
                outData.setPreCargoBoxDoorStatus2Lon(lon);
                break;
            case DRSTS3:
                outData.setPreCargoBoxDoorStatus3(onOff);
                outData.setPreCargoBoxDoorStatus3St(startTime);
                outData.setPreCargoBoxDoorStatus3Lat(lat);
                outData.setPreCargoBoxDoorStatus3Lon(lon);
                break;
            default:
                throw new IllegalArgumentException("invalid type:" + type);
        }
    }

    public void dealPoint(PointForColdChain point, OutData outData) {
        EventType[] type = EventType.values();
        int[] previous = {
                toInt(outData.getPreCargoBoxTemperature1()),
                toInt(outData.getPreCargoBoxTemperature2()),
                toInt(outData.getPreCargoBoxTemperature3()),
                toInt(outData.getPreCargoBoxTemperature4()),
                toInt(outData.getPreContainerHumidity1()),
                toInt(outData.getPreContainerHumidity2()),
                toInt(outData.getPreContainerHumidity3()),
                toInt(outData.getPreContainerHumidity4()),
                toInt(outData.getPreCargoBoxDoorStatus1()),
                toInt(outData.getPreCargoBoxDoorStatus2()),
                toInt(outData.getPreCargoBoxDoorStatus3())
        };
        int[] current = {
                point.getCargoboxtemperature1(),
                point.getCargoboxtemperature2(),
                point.getCargoboxtemperature3(),
                point.getCargoboxtemperature4(),
                point.getContainerhumidity1(),
                point.getContainerhumidity2(),
                point.getContainerhumidity3(),
                point.getContainerhumidity4(),
                point.getCargoboxdoorstatus1(),
                point.getCargoboxdoorstatus2(),
                point.getCargoboxdoorstatus3()
        };
        for (int i = 0; i < type.length; i++) {
            exec(type[i], previous[i], current[i], point, outData);
        }
        // 保存上一个点信息
        outData.shift(point);
    }

    private void exec(EventType type, int previous, int current, PointForColdChain point, OutData outData) {
        if (previous == OFF && current == ON) {
            // 记录开始时间
            setStartInfo(outData, type, new Timestamp(point.getGpsTime()), point.getLatitude(), point.getLongitude(), current);
        } else if (previous == ON && current == OFF) {
            // 生成event
            ColdChainEvent event = new ColdChainEvent();
            event.setTid(point.getTid());
            event.setType(type.code);
            event.setStartTime(getStartTime(outData, type));
            event.setEndTime(new Timestamp(point.getGpsTime()));
            event.setLatitude(getLat(outData, type));
            event.setLongitude(getLon(outData, type));
            // 判断开始时间小于结束时间，防止重跑任务时，cold_chain_info表有中间数据影响结果
            if (event.getStartTime().before(event.getEndTime())) {
                outData.getOutEvents().add(event);
            }
            // 清除开始时间
            setStartInfo(outData, type, null, null, null, current);
        }
    }

    private int toInt(Integer v) {
        if (v == null) {
            return OFF;
        }
        return v;
    }

    public enum EventType {
        //
        TMPRTR1("1"),
        TMPRTR2("2"),
        TMPRTR3("3"),
        TMPRTR4("4"),
        HMDT1("5"),
        HMDT2("6"),
        HMDT3("7"),
        HMDT4("8"),
        DRSTS1("9"),
        DRSTS2("10"),
        DRSTS3("11");

        public final String code;

        EventType(String code) {
            this.code = code;
        }
    }
}
